#pragma once

#include <fmt/core.h>
#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <spdlog/spdlog.h>

#include <fstream>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>

#include "cppguide/util/log_util.h"

template <class T>
class R {
public:
    enum Status {
        OK,
        FAILED
    };
    R() = default;
    R(T dataValue, Status statusValue) : data(dataValue), status(statusValue) {}

public:
    bool ok() {
        return Status::OK == this->status;
    }

public:
    T      data;
    Status status{OK};
};

class TestHelper {
public:
    TestHelper() {
        this->log = cppguide::LogUtil::getLogger("testhelper");
    };
    ~TestHelper() = default;

public:
    static std::shared_ptr<TestHelper> getInstance() {
        static std::shared_ptr<TestHelper> singleton = nullptr;
        static std::mutex                  singletonMutex;

        if (singleton == nullptr) {
            std::unique_lock<std::mutex> lock(singletonMutex);
            if (singleton == nullptr) {
                singleton = std::make_shared<TestHelper>();
            }
        }

        return singleton;
    }

public:
    R<std::string> readTextFile(const std::string& path) {
        R<std::string> r;

        std::ifstream file;
        file.open(path, std::ios::in);
        if (!file) {
            SPDLOG_LOGGER_ERROR(log, fmt::format("文件:{} 打开失败", path));
            r.status = R<std::string>::Status::FAILED;
            file.close();
            return r;
        }

        std::stringstream ss;
        std::string       line;
        while (!file.eof()) {
            std::getline(file, line);
            ss << line << '\n';
        }
        r.data = ss.str();
        return r;
    }

    void printJson(rapidjson::Document& doc, bool pretty = false) {
        rapidjson::StringBuffer buffer;
        if (pretty) {
            rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
            doc.Accept(writer);
        } else {
            rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
            doc.Accept(writer);
        }

        SPDLOG_LOGGER_INFO(log, fmt::format("{}", buffer.GetString()));
    }

private:
    std::shared_ptr<spdlog::logger> log;
};